<template>
<div class="parent">
    <div id="container">
    </div>
    <div id="controls">
    </div>
</div>
</template>
<script setup lang="ts">
import * as THREE from 'three';
import { onMounted } from 'vue';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import GUI from 'three/examples/jsm/libs/lil-gui.module.min.js';

onMounted(()=>{
    const renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.getElementById('container')?.appendChild(renderer.domElement);

    const fov = 75;
	const aspect = 2;
	const near = 0.1;
	const far = 5;
	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
	camera.position.z = 2;

    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.target.set(0, 0, 0);
    controls.update();

    const scene = new THREE.Scene();
    {
        const color = 0xFFFFFF;
        const intensity = 3;
        const light = new THREE.DirectionalLight(color, intensity);
        light.position.set(-1, 2, 4);
        scene.add(light);
    }

    const boxWidth = 1;
    const boxHeight = 1;
    const boxDepth = 1;
    const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
    const gui = new GUI({container:document.getElementById('controls')!!});

    function makeInstance(geometry:THREE.BufferGeometry, color:number, x:number) { 
        const material = new THREE.MeshPhongMaterial({color});
        const cube = new THREE.Mesh(geometry, material);
        scene.add(cube);
        cube.position.x = x;

        const folder = gui.addFolder( `Cube ${x}` )
        folder.addColor(material,'color').name('color').onChange(requestRenderIfNotRequested);
        folder.add(cube.scale, 'x', 0.1, 1.5).name('x').onChange(requestRenderIfNotRequested);
        folder.add(cube.scale, 'y', 0.1, 1.5).name('y').onChange(requestRenderIfNotRequested);
        folder.add(cube.scale, 'z', 0.1, 1.5).name('z').onChange(requestRenderIfNotRequested);
        return cube;
    }

    makeInstance( geometry, 0x44aa88, 0 );
	makeInstance( geometry, 0x8844aa, - 2 );
	makeInstance( geometry, 0xaa8844, 2 );

    function resizeRendererToDisplaySize(renderer:THREE.WebGLRenderer) {
        const canvas = renderer.domElement; 
        const width = canvas.clientWidth;
        const height = canvas.clientHeight;
        const needResize = canvas.width !== width || canvas.height !== height;
        if (needResize) {
            renderer.setSize(width, height, false);
        }
        return needResize;
    }

    let renderRequested:boolean|undefined = undefined;

    function render() {
        renderRequested = undefined;
        if (resizeRendererToDisplaySize(renderer)){
            const canvas = renderer.domElement;
            camera.aspect = canvas.clientWidth / canvas.clientHeight;
            camera.updateProjectionMatrix();
        }

        controls.update();
        renderer.render(scene, camera);
    }

    render();

    function requestRenderIfNotRequested() {
        if (!renderRequested) {
            renderRequested = true;
            requestAnimationFrame(render);
        }
    }


    //这种更新建立在没有动画的基础之上，当controls变化或者窗口变化的时候才更新render，可以减少渲染次数
    controls.addEventListener('change', requestRenderIfNotRequested);
    window.addEventListener('resize', requestRenderIfNotRequested);

});
</script>
<style scoped>
.parent{
    position: relative;
    width: 100%;
    height: 100%;
}
.parent > * {
    position:absolute;
}

#controls {
    right: 0;
}

</style>